---
title: Camera
description: A React component that renders a preview for the device's front or back camera.
sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-53/packages/expo-camera'
packageName: 'expo-camera'
iconUrl: '/static/images/packages/expo-camera.png'
platforms: ['android*', 'ios*', 'web']
---

import { GithubIcon } from '@expo/styleguide-icons/custom/GithubIcon';

import APISection from '~/components/plugins/APISection';
import { APIInstallSection } from '~/components/plugins/InstallSection';
import { AndroidPermissions, IOSPermissions } from '~/components/plugins/permissions';
import { BoxLink } from '~/ui/components/BoxLink';
import {
  ConfigReactNative,
  ConfigPluginExample,
  ConfigPluginProperties,
} from '~/ui/components/ConfigSection';
import { SnackInline } from '~/ui/components/Snippet';

`expo-camera` provides a React component that renders a preview of the device's front or back camera. The camera's parameters such as zoom, torch, and flash mode are adjustable. Using `CameraView`, you can take photos and record videos that are saved to the app's cache. The component is also capable of detecting bar codes appearing in the preview. Run the [example](#usage) on your device to see all these features working together.

## Installation

<APIInstallSection />

## Configuration in app config

You can configure `expo-camera` using its built-in [config plugin](/config-plugins/introduction/) if you use config plugins in your project ([Continuous Native Generation (CNG)](/workflow/continuous-native-generation/)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does **not** use CNG, then you'll need to manually configure the library.

<ConfigPluginExample>

```json app.json
{
  "expo": {
    "plugins": [
      [
        "expo-camera",
        {
          "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera",
          "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone",
          "recordAudioAndroid": true
        }
      ]
    ]
  }
}
```

</ConfigPluginExample>

<ConfigPluginProperties
  properties={[
    {
      name: 'cameraPermission',
      platform: 'ios',
      description: 'A string to set the [`NSCameraUsageDescription`](#ios) permission message.',
      default: '"Allow $(PRODUCT_NAME) to access your camera"',
    },
    {
      name: 'microphonePermission',
      platform: 'ios',
      description: 'A string to set the [`NSMicrophoneUsageDescription`](#ios) permission message.',
      default: '"Allow $(PRODUCT_NAME) to access your microphone"',
    },
    {
      name: 'recordAudioAndroid',
      platform: 'android',
      description:
        'A boolean that determines whether to enable the `RECORD_AUDIO` permission on Android.',
      default: 'true',
    },
  ]}
/>

<ConfigReactNative>

If you're not using Continuous Native Generation ([CNG](/workflow/continuous-native-generation/)) (you're using native **android** and **ios** projects manually), then you need to configure following permissions in your native projects:

**Android**

- `expo-camera` automatically adds `android.permission.CAMERA` permission to your project's **android/app/src/main/AndroidManifest.xml**. If you want to record videos with audio, include `RECORD_AUDIO` permission:

  ```xml
  <!-- Added permission -->
  <uses-permission android:name="android.permission.CAMERA" />

  <!-- Only add when recording videos with audio -->
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
  ```

- Then, adjust the **android/build.gradle** file to add new maven block after all other repositories as show below:

  ```groovy
  allprojects {
    repositories {
        // * Your other repositories here *
        // * Add a new maven block after other repositories / blocks *
        maven {
            // expo-camera bundles a custom com.google.android:cameraview
            url "$rootDir/../node_modules/expo-camera/android/maven"
        }
    }
  }
  ```

**iOS**

- Add `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` keys to your project's **ios/[app]/Info.plist**:

  ```xml
  <key>NSCameraUsageDescription</key>
  <string>Allow $(PRODUCT_NAME) to access your camera</string>
  <key>NSMicrophoneUsageDescription</key>
  <string>Allow $(PRODUCT_NAME) to access your microphone</string>
  ```

</ConfigReactNative>

## Usage

> **warning** Only one Camera preview can be active at any given time. If you have multiple screens in your app, you should unmount `Camera` components whenever a screen is unfocused.

<SnackInline label='Basic Camera Usage' dependencies={['expo-camera']}>

```tsx
import { CameraView, CameraType, useCameraPermissions } from 'expo-camera';
import { useState } from 'react';
import { Button, StyleSheet, Text, TouchableOpacity, View } from 'react-native';

export default function App() {
  const [facing, setFacing] = useState<CameraType>('back');
  const [permission, requestPermission] = useCameraPermissions();

  if (!permission) {
    // Camera permissions are still loading.
    return <View />;
  }

  if (!permission.granted) {
    // Camera permissions are not granted yet.
    return (
      <View style={styles.container}>
        <Text style={styles.message}>We need your permission to show the camera</Text>
        <Button onPress={requestPermission} title="grant permission" />
      </View>
    );
  }

  function toggleCameraFacing() {
    setFacing(current => (current === 'back' ? 'front' : 'back'));
  }

  return (
    <View style={styles.container}>
      <CameraView style={styles.camera} facing={facing} />
      <View style={styles.buttonContainer}>
        <TouchableOpacity style={styles.button} onPress={toggleCameraFacing}>
          <Text style={styles.text}>Flip Camera</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  message: {
    textAlign: 'center',
    paddingBottom: 10,
  },
  camera: {
    flex: 1,
  },
  buttonContainer: {
    position: 'absolute',
    bottom: 64,
    flexDirection: 'row',
    backgroundColor: 'transparent',
    width: '100%',
    paddingHorizontal: 64,
  },
  button: {
    flex: 1,
    alignItems: 'center',
  },
  text: {
    fontSize: 24,
    fontWeight: 'bold',
    color: 'white',
  },
});
```

</SnackInline>

### Advanced usage

<BoxLink
  title="Camera app example"
  description="A complete example that shows how to take a picture and display it. Written in TypeScript."
  Icon={GithubIcon}
  href="https://github.com/expo/examples/tree/master/with-camera"
/>

## Web support

Most browsers support a version of web camera functionality, you can check out the [web camera browser support here](https://caniuse.com/#feat=stream). Image URIs are always returned as base64 strings because local file system paths are unavailable in the browser.

### Chrome `iframe` usage

When using **Chrome versions 64+**, if you try to use a web camera in a cross-origin iframe nothing will render. To add support for cameras in your iframe simply add the attribute `allow="microphone; camera;"` to the iframe element:

```html
<iframe src="..." allow="microphone; camera;">
  <!-- <CameraView /> -->
</iframe>
```

## API

```js
import { CameraView } from 'expo-camera';
```

<APISection packageName="expo-camera" apiName="Camera" exposeAllClassPropsInSidebar />

## Permissions

### Android

This package automatically adds the `CAMERA` permission to your app. If you want to record videos with audio, you have to include the `RECORD_AUDIO` in your **app.json** inside the [`expo.android.permissions`](../config/app/#permissions) array.

<AndroidPermissions permissions={['CAMERA', 'RECORD_AUDIO']} />

### iOS

The following usage description keys are used by this library:

<IOSPermissions permissions={['NSCameraUsageDescription', 'NSMicrophoneUsageDescription']} />
